#ifndef CELLMODEL
#define CELLMODEL

#include "particles.h"
#include "voigt.h"
#include "messages.h"

#include <string>
#include <vector>

using std::string;
using std::vector;

class CellSolver;

/**
 * class Cell 
 * defines the inner environment of cell
 * cell handles everything inside itself
 * if more information is required it asks
 * cellSolver modul which provides required 
 * data and compuation
 */
class CellModel {

private:
	
	/** unique id of cell */
	int cellId;

	/** possible comment if needed */
	string comment;

	/** 
	 * pointer to cell solver  
	 * it provides the only connection to outer world
	 * of simulation 
	 */
	CellSolver * cellSolver;

	/** list of membrane particles */
	vector<Particle> memParticles;

	/** list of inner particles */
	vector<Particle> innParticles;

	/** list of membrane voigts */
	vector<Voigt> memVoigts;

	/** list of inner voigts */
	vector<Voigt> innVoigts;


	/**********************************************
	 * private methods:
	 **********************************************/


	/** adds new membrane particle */ 
	void addMemParticle( Particle & particle );

	/** adds new inner particle */ 
	void addInnParticle( Particle & particle );

	/** adds new membrane voigt */ 
	void addMemVoigt( Voigt & voigt );

	/** adds new inner voigt */
	void addInnVoigt( Voigt & voigt );

	/** checks if the step is from interval (0,1) */
	bool stepIsOk( double step );

	/** returns true if particle is inner particle */
	bool isInnerParticle( Particle particle );


    /**********************************************
	 * lifecycle methods (used by recompute):
	 **********************************************/
	
	/** gets external force for every particle from cell solver */
	void getExternalForces( double step );

	/** 
	 * recomputes particle positions according applied 
	 * internal and external forces
	 */
	void recomputeParticlePositions( double step );

	/** moves particle to desired position 
	 * @param newPositions precondition is that messages
	 */
	void moveParticle( Message message );

    /** updates external force of particle */
	void updateParticleExtForce( Message message );

	
public:

	/** Constructor  TODO hide as private*/
	CellModel();

	/** Constructor */
	CellModel( int cellId, string comment, CellSolver * cellSolver );

	/** Destructor */
	~CellModel();


	/** 
	 * adds new particle 
	 * @param x 
	 * @param y
	 * @param z
	 */
	void addNewParticle( Particle particle );

	/** 
	 * adds new voigt element between two particles
	 * @param start id of starting particle
	 * @param end id of ending particle
	 * @param springConst spring constant
	 * @param restLength rest length of spring
	 * @param viscosityConst viscosity constant
	 * @param length length of voigt
	 */
	void addNewVoigt( 
		int start, 
		int end, 
		double springConst,
		double restLength,
		double viscosityConst, 
		double length );


	/** set new cell solver to cell */
	void setCellSolver( CellSolver * cellSolver );


	/******************************************************
	 * communication methods
	 ******************************************************/

	/** 
	 * main mean of communication between cell and 
	 * cellsolvers( other modules) 
	 * message is always sent to cell solver attached to cell
	 * @param cellsolver cell solver helping cell solve computation
	 * @param message message to send 
	 */
	void send( Message * message );

	/**
	 * processing of reveived message
	 * directly or in queue
	 */
	void receive( Message * message );

	
};




#endif //CELLMODEL